package com.itmuch.box.util.mail;

import java.io.IOException;
import java.io.StringReader;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.multipart.MultipartFile;

import com.itmuch.box.core.exception.BusinessException;
import com.itmuch.box.domain.email.domain.Email;
import com.itmuch.box.service.config.ConfigService;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

/**
 * 发送邮件 工具类
 * @see http://www.blogjava.net/tangzurui/archive/2008/12/08/244953.html
 * @see http://blog.csdn.net/ajun_studio/article/details/7347644
 * @author zhouli
 */
@Component
public class MailUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(MailUtil.class);

    @Resource
    private JavaMailSenderImpl mailSender;
    @Resource
    private ConfigService configService;

    /**
     * 同步发送邮件. 如果想要用异步发送邮件, 可在service中使用@Async注解.
     * 原因: 如果在本类中使用异步发送, 将可能造成在service中事务无法回滚的问题.
     * @param to 收件人
     * @param root freemarker模型对象
     * @param type 邮件类型
     * @throws BusinessException 异常
     * @see http://www.blogjava.net/tangzurui/archive/2008/12/08/244953.html
     * @see http://blog.csdn.net/ajun_studio/article/details/7347644
     * @see 异步发送邮件: http://blog.csdn.net/dr_lf/article/details/6014948
     */
    public void sendMail(String to, Map<String, Object> root, Type type) throws BusinessException {
        try {
            Email email = this.genEmail(to, root, type);
            this.send(email);
        } catch (Exception e) {
            LOGGER.warn("发送邮件发生异常, {}", e);
            throw new BusinessException("发送邮件发生异常.");
        }
    }

    /**
     * 生成html模板字符串
     * @param root 存储动态数据的map
     * @return
     * @throws IOException
     * @throws TemplateException
     */
    public Email genEmail(String to, Map<String, Object> root, Type type) throws IOException, TemplateException {
        Email email = new Email();
        Map<String, String> genMap = this.configService.findByModuleAndName4Map("site", "mail");
        String host = genMap.get("mail.host");
        String port = genMap.get("mail.port");
        String username = genMap.get("mail.username");
        String password = genMap.get("mail.password");
        String auth = genMap.get("mail.smtp.auth");
        email.setHost(host);
        email.setPort(Integer.parseInt(port));
        email.setUsername(username);
        email.setPassword(password);
        email.setAuth(auth);
        email.setTo(to);

        String subject = null;
        String text = null;
        if (Type.REG.equals(type)) {
            subject = genMap.get("mail.reg.subject");
            text = genMap.get("mail.reg.text");
        }

        String htmlText = "";
        Template template = new Template("name", new StringReader(text), new Configuration(Configuration.VERSION_2_3_23));
        htmlText = FreeMarkerTemplateUtils.processTemplateIntoString(template, root);

        email.setSubject(subject);
        email.setContent(htmlText);
        return email;

    }

    public void send(Email email) throws MessagingException, IOException {
        String username = email.getUsername();
        Map<String, String> genMap = this.configService.findByModuleAndName4Map("site", "mail");
        this.mailSender.setHost(email.getHost());
        this.mailSender.setPort(email.getPort());
        this.mailSender.setUsername(username);
        this.mailSender.setPassword(email.getPassword());
        Properties pro = new Properties();
        pro.setProperty("mail.smtp.auth", email.getAuth());
        this.mailSender.setJavaMailProperties(pro);

        String from = genMap.get("mail.from");

        MimeMessage mime = this.mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mime, true, "utf-8");
        // 发件人
        String nick = MimeUtility.encodeText(from);
        helper.setFrom(new InternetAddress(username, nick));
        // 收件人
        helper.setTo(email.getTo());
        // 邮件主题
        helper.setSubject(email.getSubject());
        // 抄送
        String cc = email.getCc();
        // 抄送
        if (!StringUtils.isEmpty(cc)) {
            String ccRep = cc.replaceAll(" ", "");
            String[] ccArr = ccRep.split(";");
            helper.setCc(ccArr);
        }
        // 密送
        String bcc = email.getBcc();
        if (!StringUtils.isEmpty(bcc)) {
            helper.setBcc(bcc);
        }
        // 回复到
        String replyTo = email.getReplyTo();
        if (!StringUtils.isEmpty(replyTo)) {
            helper.setReplyTo(replyTo);
        }
        // 内容
        helper.setText(email.getContent(), true);

        //处理附件
        List<MultipartFile> attachments = email.getAttachments();
        if ((attachments != null) && !attachments.isEmpty()) {
            for (MultipartFile file : attachments) {
                if ((file == null) || file.isEmpty()) {
                    continue;
                }
                String fileName = file.getOriginalFilename();
                try {
                    fileName = new String(fileName.getBytes("utf-8"), "ISO-8859-1");
                } catch (Exception e) {
                }
                helper.addAttachment(fileName, new ByteArrayResource(file.getBytes()));
            }
        }
        // 内嵌资源，这种功能很少用，因为大部分资源都在网上，只需在邮件正文中给个URL就足够了.
        // helper.addInline("logo", new ClassPathResource("logo.gif"));

        this.mailSender.send(mime);
        LOGGER.debug("发送邮件成功, email = {}", new Object[] { email });
    }

    enum Type {
        REG, FORGET_MAIL;
    }

}
